package com.ruan.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruan.common.Code;
import com.ruan.common.Result;
import com.ruan.mapper.FileMapper;
import com.ruan.mapper.ParticipantMapper;
import com.ruan.mapper.ProjectMapper;
import com.ruan.pojo.Employee;
//import com.ruan.pojo.FileDownloadResponse;
import com.ruan.pojo.FileEntity;
import com.ruan.pojo.Participant;
import com.ruan.pojo.Project;
import com.ruan.service.EmployeeService;
import com.ruan.service.FileService;
import com.ruan.service.ProjectService;
import com.ruan.utils.AliOSSUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.Count;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
@RestController
@RequestMapping("/upload")
public class FileUploadController {

    @Autowired
    private ProjectService projectService;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private FileService fileService;
    @Autowired
    private FileMapper fileMapper;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private ParticipantMapper participantMapper;

    @Autowired
    private AliOSSUtils aliOSSUtils;

    //必须是org.springframework.beans.factory.annotation提供的Value
    @Value("${kejiu.path}")
    private String basePath;

//    当用户上传文件时，Spring框架会将上传的文件暂存到内存或磁盘的临时位置，
//    并将其封装成MultipartFile对象。在处理文件上传的方法中，可以通过MultipartFile
//    对象来获取上传文件的内容、文件名、大小等信息，并进一步处理这些文件数据。
    @PostMapping("/upload")//(io流的transferTo方法实现)
    @Transactional
    public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file,
                                                   @RequestParam("projectId") Long projectId,
                                                   @RequestParam(value = "employeeId", required = false) Long employeeId) {
        //检查项目是否存在
        Project project = projectService.getById(projectId);
        if (project == null) {
            return ResponseEntity.badRequest().body("项目不存在");
        }
        // 获取上传文件的原始文件名
        String originalFilename = file.getOriginalFilename();
//        System.out.println("源文件名是："+originalFilename);
//        if(employeeId != null){
//            Employee employee = employeeService.getById(employeeId);
//            if (employee == null) {
//                return ResponseEntity.badRequest().body("请先给项目指定负责人");
//            }
//        }

//        System.out.println("employee是"+employee);

         // 获取文件后缀名
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);

        // 判断(后缀名)文件类型是否符合要求.doc,.docx,.txt,.xls,.xlsx,.zip,.rar,.7z,.html,.css,.xml,.pdf,.mp3,.pptx,.ppt,.mp4
        if ("doc".equals(fileType) || "docx".equals(fileType)  || "txt".equals(fileType)
                || "xls".equals(fileType)  || "xlsx".equals(fileType)  || "zip".equals(fileType)
            || "rar".equals(fileType)  || "7z".equals(fileType)  || "html".equals(fileType)
                || "css".equals(fileType)  || "xml".equals(fileType)  || "pdf".equals(fileType)
                || "mp3".equals(fileType) || "ppt".equals(fileType) || "pptx".equals(fileType)
                || "mp4".equals(fileType) || "flac".equals(fileType) || "jpg".equals(fileType)
                || "png".equals(fileType) || "jpeg".equals(fileType)){
// 保存文件到指定目录
            try {
                 //使用UUID重新生成文件名，防止文件名称重复，造成文件覆盖
                String UUIDFilename = UUID.randomUUID().toString();
                //文件上传后的目标路径。basePath
                File destFile = new File
                        (basePath + UUIDFilename + "---" + originalFilename);

                //通过file.transferTo(destFile)方法将上传的文件保存到目标路径中。
                //文件首先会被存储在服务器的临时目录中。然后通过transferTo()
                //方法，将文件内容从临时目录移动或复制到目标路径中。
                file.transferTo(destFile);

                //存储文件信息到数据库
                FileEntity fileEntity = new FileEntity();
                fileEntity.setFileName(UUIDFilename + "---" + originalFilename);
                //组长可以查到是谁上传的
                Employee employee = employeeService.getById(employeeId);
                if(employee != null){
                    fileEntity.setEmployeeId(employeeId);
                }
                //组长可以查看该项目
                fileEntity.setProjectId(projectId);
                //存入数据库，要的时候组长再根据这个下载
                fileService.save(fileEntity);
                return ResponseEntity.ok("文件上传成功");
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseEntity.badRequest().body("文件上传失败");
            }
        } else {
            // 文件类型不符合要求，返回错误信息
            return ResponseEntity.badRequest().body("只能上传.doc,.docx,.txt,.xls," +
                    ".xlsx,.zip,.rar,.7z,.html,.css,.xml,.pdf,.mp3,.ppt," +
                    ".pptx,.mp4,.jpg,.png,.jpeg格式的文件");
        }
    }


    //下载按钮的消失与出现
    @GetMapping("/canDownload/{projectId}")
    public Result canDownload(@PathVariable Long projectId,
                              //参与员工id
                              @RequestParam("employeeId") Long employeeId){
        LambdaQueryWrapper<FileEntity> queryWrapper = new LambdaQueryWrapper<>();
        //这个项目必须有文件
        queryWrapper.eq(FileEntity::getProjectId, projectId);
        queryWrapper.eq(FileEntity::getIsDelete, FileEntity.IsDelete.exist);
        LambdaQueryWrapper<Participant> queryWrapper1 = new LambdaQueryWrapper<>();
        //必须是这个项目的参与人员
        queryWrapper1.eq(Participant::getProjectId, projectId);
        queryWrapper1.eq(Participant::getEmployeeId, employeeId);
        int count = fileMapper.selectCount(queryWrapper);
        int count1 = participantMapper.selectCount(queryWrapper1);
        if (count == 0 || count1 == 0){
            return new Result(Code.SELECT_ERR,"没有下载权限或者没有文件可以下载");
        }
        return new Result(Code.SELECT_OK,"允许下载");
    }

//    1.使用FileInputStream和FileOutputStream：通过创建FileInputStream来读取文件内容，
//    然后使用FileOutputStream将文件内容写入到目标位置，实现文件的上传和下载。
    //下载成压缩包
//    @SneakyThrows
    @GetMapping("/download/{projectId}")//ResponseEntity<Resource>
    public ResponseEntity<Resource> getFile(@PathVariable Long projectId,
                                     //参与员工id
                                     @RequestParam("employerId") Long employerId,
                                     //项目负责人id@RequestParam("employeeId") Long employeeId
                                     @RequestParam(value = "employeeId", required = false) Long employeeId){
        // 根据projectId和员工id获取文件信息
        //FileEntity fileEntity = fileService.getProjectByIdAndEmployeeId(projectId,employeeId);
        //log.info("下载传的参数是:{},{},{}",projectId,employerId,employeeId);
        //根据项目id查询项目负责人id,用于判断是否有权限下载
//        LambdaQueryWrapper<Project> projectQueryWrapper = new LambdaQueryWrapper<>();
//        projectQueryWrapper.eq(Project::getId, projectId);
//        Project project1 = projectMapper.selectOne(projectQueryWrapper);
        Project project1 = projectMapper.selectById(projectId);
        //查查是否是这个项目的参与人员
        LambdaQueryWrapper<Participant> participantQueryWrapper = new LambdaQueryWrapper<>();
        participantQueryWrapper.eq(Participant::getProjectId, projectId);
        participantQueryWrapper.eq(Participant::getEmployeeId, employerId);
        int count = participantMapper.selectCount(participantQueryWrapper);
        //负责人id不匹配
        if(employeeId != null){
          if(!employeeId.equals(project1.getEmployeeId()) && count==0){
               return ResponseEntity.notFound().build();
          }
        }
        LambdaQueryWrapper<FileEntity> queryWrapper = new LambdaQueryWrapper<>();
        //下载哪个项目的文件
        queryWrapper.eq(FileEntity::getProjectId, projectId);
        queryWrapper.eq(FileEntity::getIsDelete, FileEntity.IsDelete.exist);
        Integer count1 = fileMapper.selectCount(queryWrapper);
        if (count1 == 0) {
            return ResponseEntity.notFound().build();
        }
        //下载的是谁的文件
        //queryWrapper.eq(FileEntity::getEmployeeId, employeeId);//组员id匹配
        Project project = new Project();
        List<FileEntity> fileEntityList = fileMapper.selectList(queryWrapper);
        if (fileEntityList != null && fileEntityList.size() > 0) {
            // 创建临时目录用于存放要下载的文件basePath
            File tempDir = new File(basePath + "tempDir");
            if (!tempDir.exists()) {
                tempDir.mkdirs();
            }
            //存放即将压缩的所有文件
            List<File> filesToZip = new ArrayList<>();
            for (FileEntity fileEntity : fileEntityList) {
                project = projectService.getById(fileEntity.getProjectId());
                //该项目不为空，且这个文件是这个项目的文件 && project.getEmployeeId().equals(employeeId)
                if (project != null) {
                    String filePath = basePath + fileEntity.getFileName();
                    //即将操作的文件
                    File file = new File(filePath);
                    // 创建一个简短的 UUID
                    //String shortUUID = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
                    // 取前8个字符
                    // 如果文件存在且为文件类型
                    if (file.exists() && file.isFile()) {
                        //创建一个目标文件destFile，这个目标文件是在临时目录（tempDir）下，
                        // 目标文件destFile的文件名就是原文件名
                        File destFile = new File(tempDir,
                                fileEntity.getFileName());
                        try {
                            //将一个文件从源路径复制到目标路径(Files是一个类)
                            //将file表示的文件(原文件)复制到destFile表示的目标路径中
                            //System.out.println("复制文件：" + file.toPath() + " 到目标路径："
                            //        + destFile.getAbsolutePath());
                            Files.copy(file.toPath(),
                                    destFile.toPath(),
                                    StandardCopyOption.REPLACE_EXISTING);
                            //如果目标路径已经存在同名文件，如果目标文件不存在，则会创建一个新的文件并将源文件内容复制过去。
//                            System.out.println("destFile是："+destFile);
//                            System.out.println("destFile.getName()是："+destFile.getName());
                            //截取文件名，去掉UUID
                            //String originalFileName = destFile.getName().substring(destFile.getName().indexOf("---") + 2);
                            filesToZip.add(destFile);
                            //一个个的存文件进去，以便后续的压缩
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }else{//只有在if里面return了，才不用写else
                    //项目不存在
                    return ResponseEntity.notFound().build();
                }

            }
            //即将压缩的文件列表拿到文件了。。。
            if (filesToZip.size() > 0) {
                // 创建压缩文件
//                String zipFilePath = basePath + "tempDir\\downloadedFiles.zip";
//                System.out.println("project.getPid()是"+project.getPid());
                String zipFilePath = basePath + "tempDir\\" + project.getProjectName() + "-" + project.getPid() + ".zip";
                try (FileOutputStream fos = new FileOutputStream(zipFilePath);
                     //通过 ZipOutputStream 将压缩文件的输出流 fos 进行初始化，
                     // 这个输出流指向要生成的ZIP文件。
                     ZipOutputStream zos = new ZipOutputStream(fos)) {
                    //遍历filesToZip列表中的每个文件fileToZip
                    for (File fileToZip : filesToZip) {
                        //对于每个文件，创建一个ZipEntry对象zipEntry，
                        //表示ZIP文件中的一个条目，其名称为当前文件的名称。
                        ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
                        //使用zos.putNextEntry(zipEntry)来开始写入新的ZIP文件条目
                        zos.putNextEntry(zipEntry);
                        //调用Files.copy()方法
                        //将当前文件的内容复制到ZipOutputStream中，
                        //实现将文件内容写入ZIP文件的功能。
                        Files.copy(fileToZip.toPath(), zos);
                        //结束当前ZIP文件条目的写入
                        zos.closeEntry();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    return ResponseEntity.badRequest().body(null);
                }

                // 提供压缩文件给组长下载
                try {
                    //通过UrlResource创建一个资源对象resource，表示要下载的ZIP文件的路径
                    Resource resource = new UrlResource(Paths.get(zipFilePath).toUri());
                    //      资源存在                 资源可读
                    if (resource.exists() && resource.isReadable()) {
//                        System.out.println("项目名是：" + project.getProjectName());
//                        System.out.println("resource是："+resource);
                        //将资源作为响应体返回，实现文件下载功能
                        try {
                            //解决中文文件名乱码
                            String encodedFileName = URLEncoder.encode
                                    (project.getProjectName() + "-" +
                                            project.getPid() + ".zip", "UTF-8");

//                            try {
//                                //TODO 删除临时建立的文件夹
//                                FileUtils.deleteDirectory(tempDir);
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }

//                            String message = "";
//                            if (resource.contentLength() > 20 * 1024 * 1024) {
//                                message = "文件尺寸过大，请稍等...";
//                            } else {
//                                message = "正在准备下载，请稍候...";
//                            }

//                           //构建自定义响应对象
//                            FileDownloadResponse response = new FileDownloadResponse(message, resource);
//
//                            return ResponseEntity.ok()
//                                    .header(HttpHeaders.CONTENT_DISPOSITION,
//                                            "attachment; filename=\"" + encodedFileName + "\"")
//                                    .body(new InputStreamResource(response));

// 使用 InputStreamResource 返回文件流，使用  InputStreamResource  来包装文件流，而不是直接返回  Resource
                            InputStreamResource inputStreamResource = null;
                            try {
                                inputStreamResource = new InputStreamResource(resource.getInputStream());
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                            try {
                                return ResponseEntity.ok()
                                        .header(HttpHeaders.CONTENT_DISPOSITION,
                                                "attachment; filename=\"" +
                                                        encodedFileName + "\"")
                                        //确保设置  contentLength  以便于浏览器正确处理下载文件。
                                        .contentLength(resource.contentLength())
                                        .contentType(MediaType.APPLICATION_OCTET_STREAM)
//                                        .contentType(MediaType.APPLICATION_JSON) // 设置为 JSON
                                        .body(inputStreamResource);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

//                         return ResponseEntity.ok()
//                                    .header(HttpHeaders.CONTENT_DISPOSITION,
//                                            "attachment; filename=\"" +
//                                                    encodedFileName + "\"")
//                                    .body(resource);
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    } else {
                        //404 Not Found
                        return ResponseEntity.notFound().build();
                    }
                    //资源路径不合法
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    //返回400 Bad Request
                    return ResponseEntity.badRequest().body(null);
                }
            } else {
                return ResponseEntity.notFound().build();
            }
        }
        return ResponseEntity.notFound().build();
    }


    /**
     * 单文件下载
     * @param projectId
     * @param fileId
     * @return
     */
@SneakyThrows
@GetMapping("/adminDownload/{projectId}")
public ResponseEntity<Resource> getFile(@PathVariable Long projectId,
                                        //@RequestParam("employerId") Long employerId,
                                        @RequestParam("fileId") String fileId) {
    LambdaQueryWrapper<FileEntity> queryWrapper = new LambdaQueryWrapper<>();
    // 查询特定项目和文件
    queryWrapper.eq(FileEntity::getProjectId, projectId);
    queryWrapper.eq(FileEntity::getId, fileId);

    List<FileEntity> fileEntityList = fileMapper.selectList(queryWrapper);
    if (fileEntityList != null && fileEntityList.size() > 0) {
        // 获取第一个文件实体，这是单个文件下载
        FileEntity fileEntity = fileEntityList.get(0);
        //System.out.println("拿到文件实体了吗:"+fileEntity);
        Project project = projectService.getById(fileEntity.getProjectId());
//        System.out.println("能获取到BaseContext"+BaseContext.getCurrentId()+"吗??");
//        System.out.println("哪个项目的："+project);
        if (project != null) {
            String filePath = basePath + fileEntity.getFileName();
            //System.out.println("filePath是："+filePath);
//String encodedPath = URLEncoder.encode(filePath, StandardCharsets.UTF_8.toString());
//File file = new File(URLDecoder.decode(encodedPath, StandardCharsets.UTF_8.toString()));
            File file = new File(filePath);
//            System.out.println("文件是："+file);
            if (file.exists() && file.isFile()) {
                Resource resource = new FileSystemResource(file);
                //内容类型设置为  application/octet-stream ，这是一个通用的二进制流类型，
                // 通常用于文件下载。虽然可以设置为更具体的类型（如  image/png  或  application/pdf ），
                // 但  application/octet-stream  是安全的选择，浏览器会将其视为附件进行下载
                //为什么打开这句话，就下载不了
                //String contentType = "application/octet-stream"; // You can set a more specific content type if known
                // 设置响应头，告诉浏览器下载文件
                //String headerValue = "attachment; filename=\"" + fileEntity.getFileName() + "\"";
              if (resource.exists() && resource.isReadable()) {
//                System.out.println("resource是："+resource);
                Employee employee = employeeService.getById(fileEntity.getEmployeeId());
                //将资源作为响应体返回，实现文件下载功能
                // 获取文件名
                String filename = file.getName();
//                System.out.println("文件名： "+filename);
//                String noUUID = filename.substring(0, filename.indexOf("---"));
//                System.out.println("noUUID截取的是UUID的部分："+noUUID);
                String originalFileName = filename.substring(filename.indexOf("---") + 3);
                //System.out.println("originalFileName截取的是UUID后面的部分："+originalFileName);
                // 获取文件后缀名
//                String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
//                System.out.println("文件后缀名：" + ext);

                  String EmployeeName = null;
                  // 解决中文文件名乱码
                  String encodedFileName = null;
                  if(employee!=null){
                      EmployeeName = employee.getName() + "-";
                      // 解决中文文件名乱码
                      encodedFileName = URLEncoder.encode
                              (EmployeeName + originalFileName, "UTF-8");
                  }else{
                      // 解决中文文件名乱码
                      encodedFileName = URLEncoder.encode
                              (originalFileName, "UTF-8");
                  }

                // 解决中文文件名乱码
                // 设置响应头，告诉浏览器下载文件
                String headerValue = "attachment; filename=\"" + encodedFileName + "\"";
//                String contentType = Files.probeContentType(file.toPath()); // 获取文件 MIME 类型
//                  System.out.println("文件类型是："+contentType);
                  //System.out.println("headerValue是"+headerValue);
                return ResponseEntity.ok()
                        //为什么打开这句话，就下载不了
//                        .contentType(MediaType.parseMediaType(contentType))
                        .header(HttpHeaders.CONTENT_DISPOSITION, headerValue)
                        .body(resource);
              }
            }
            // 文件不存在
            return ResponseEntity.notFound().build();
        }
        // 项目不存在
        return ResponseEntity.notFound().build();
    }
    // 文件实体列表为空
    return ResponseEntity.notFound().build();
}

    /**
     * 在回收站下载文件
     * @param fileId
     * @return
     */
    @SneakyThrows
    @GetMapping("/trashDownload")
    public ResponseEntity<Resource> getTashFile(@RequestParam("fileId") String fileId) {
        LambdaQueryWrapper<FileEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 查询特定项目和文件
        queryWrapper.eq(FileEntity::getId, fileId);
        //必须是软删除的文件
        queryWrapper.eq(FileEntity::getIsDelete, FileEntity.IsDelete.deleted);

        List<FileEntity> fileEntityList = fileMapper.selectList(queryWrapper);
        if (fileEntityList != null && fileEntityList.size() > 0) {
            // 获取第一个文件实体，这是单个文件下载
            FileEntity fileEntity = fileEntityList.get(0);
                String filePath = basePath + fileEntity.getFileName();
                File file = new File(filePath);
//                System.out.println("文件是："+file);
                if (file.exists() && file.isFile()) {
                    Resource resource = new FileSystemResource(file);
                    if (resource.exists() && resource.isReadable()) {
//                        System.out.println("resource是："+resource);
                        Employee employee = employeeService.getById(fileEntity.getEmployeeId());
                        //将资源作为响应体返回，实现文件下载功能
                        // 获取文件名
                        String filename = file.getName();
//                        System.out.println("文件名： "+filename);
                        String originalFileName = filename.substring(filename.indexOf("---") + 3);
                        String EmployeeName = null;
                        // 解决中文文件名乱码
                        String encodedFileName = null;
                        if(employee!=null){
                            EmployeeName = employee.getName() + "-";
                            // 解决中文文件名乱码
                            encodedFileName = URLEncoder.encode
                                    (EmployeeName + originalFileName, "UTF-8");
                        }else{
                            // 解决中文文件名乱码
                            encodedFileName = URLEncoder.encode
                                    (originalFileName, "UTF-8");
                        }

                        // 设置响应头，告诉浏览器下载文件
                        String headerValue = "attachment; filename=\"" + encodedFileName + "\"";
                        return ResponseEntity.ok()
                                //.contentType(MediaType.parseMediaType(contentType)) // 确保设置了正确的类型
                                //为什么打开这句话，就下载不了
//                        .contentType(MediaType.parseMediaType(contentType))
                                .header(HttpHeaders.CONTENT_DISPOSITION, headerValue)
                                .body(resource);
                    }
                }
                // 文件不存在
                return ResponseEntity.notFound().build();
        }
        // 文件实体列表为空
        return ResponseEntity.notFound().build();
    }
}
